package com.filldream.fastboot.web.config.request;

import cn.hutool.crypto.digest.MD5;
import com.filldream.fastboot.common.exception.GlobalException;
import com.filldream.fastboot.common.entity.ErrorCode;
import com.filldream.fastboot.common.entity.RequestDTO;
import com.filldream.fastboot.common.util.Assert;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.util.Arrays;
import java.util.List;

/**
 * PassToken校验工具
 * 用于公共接口或敏感接口的校验，防止Postman等恶意调用
 * @author RickSun
 */
@Slf4j
public class PassTokenVerify {

    //放行方法
    private final List<String> METHODS = Arrays.asList("GET", "POST", "PUT", "DELETE", "HEAD");
    //放行Type
    private final List<String> TYPES = Arrays.asList("pc", "app", "wx", "mp", "common");
    //加密糖
    private static final  String SUGAR = "FastBoot.RickSun.Sugar";
    //30秒的过期时间
    private static final long overTime = 30*1000L;

    /**
     * 校验token的促成部分是否缺失或不完整
     * type-time-token
     * @param token
     */
    public String[] checkTokenPart(String token, RequestDTO requestSTO ){

        checkUrl(requestSTO.getUri(),requestSTO.getMethodType());

        //检验token是否为空
        if(StringUtils.isBlank(token)){
            log.error("Invalid Request Token(Empty Token).");
            throw new GlobalException(ErrorCode.AUTH_ERR.reMsg(),"Invalid Request Token(Empty Token).");
        }

        String[] split = token.split("-");

        //校验token长度
        if(split == null || split.length != 3){
            log.error("Invalid Request Token Length.");
            throw new GlobalException(ErrorCode.AUTH_ERR.reMsg());
        }

        //校验接口类型
        if( StringUtils.isBlank(split[0]) || !TYPES.contains(split[0])){
            log.error("Invalid Token Type");
            throw new GlobalException(ErrorCode.AUTH_ERR.reMsg() );
        }

        //校验时间
        Assert.isBoolean( StringUtils.isBlank(split[1]),ErrorCode.AUTH_ERR.reMsg() );
        long expireTime = Long.parseLong(split[1]); //传过来的时间
        //传过来的时间误差在15秒
        long nowTime = System.currentTimeMillis() - expireTime;
        Assert.isBoolean( nowTime > overTime,ErrorCode.AUTH_ERR.reMsg() );



        if(StringUtils.isBlank(split[2])){
            log.error("Invalid Request Token Sign");
            throw new GlobalException(ErrorCode.AUTH_ERR.reMsg());
        }else{
            String s = signParam(split[0], requestSTO.getUri(),Long.valueOf(split[1]),SUGAR);
            if(!s.equals(split[2])){
                log.error("Invalid Request Token Sign");
                throw new GlobalException(ErrorCode.AUTH_ERR.reMsg());
            }
        }

        return split;
    }

    /**
     * 校验请求
     * @param urlPath
     * @param method
     */
    public void checkUrl(String urlPath,String method){
        if ( StringUtils.isBlank(urlPath) ) {
            log.error("Invalid Url Path");
            throw new GlobalException(ErrorCode.AUTH_ERR.reMsg());
        }
        if (StringUtils.isBlank(method) || !METHODS.contains(method) ) {
            log.error("Invalid Request Method");
            throw new GlobalException(ErrorCode.AUTH_ERR.reMsg());
        }
    }

    /**
     * Md5加密参数
     * @param type  请求类型，如app、pc等
     * @param urlPath   请求地址
     * @param expireTime    当前时间,Unix timestamp https://www.bejson.com/convert/unix/
     * @param sugar 加密糖
     * @return
     */
    public static String signParam( String type,String urlPath,Long expireTime,String sugar) {
        return new MD5().digestHex( String.format("%s-%s-%s-%s", type, urlPath,expireTime, sugar) );
    }

    /**
     * 加密完整
     * @param type  请求类型，如app、pc等
     * @param urlPath   请求地址
     * @param expireTime    当前时间,Unix timestamp https://www.bejson.com/convert/unix/
     * @param sugar 加密糖
     * @return
     */
    public static String sign( String type,String urlPath,Long expireTime,String sugar){
        String sbSign = String.format("%s-%s", type,expireTime);
        return sbSign + "-" + signParam(type,urlPath,expireTime,sugar);
    }

    public static String getSUGAR() {
        return SUGAR;
    }

}